package com.lgCore.clientInvok;

import com.alibaba.fastjson.JSON;
import com.lgCore.util.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Set;

/**
 * rpc接口调用入口
 * <p>
 * 注入rpc接口类
 * ligang 2020/05/07
 */
public class ClassPathRpcScanner extends ClassPathBeanDefinitionScanner {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    //包名路径
    private String packPageName;
    private RpcFactoryBean<?> rpcFactoryBean = new RpcFactoryBean<Object>();

    private Class<? extends Annotation> annotationClass;

    public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
        this.annotationClass = annotationClass;
    }

    public ClassPathRpcScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public Set<BeanDefinitionHolder> doScan(String... basePackages) {

        this.packPageName = basePackages[0];
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            logger.warn("No RPC mapper was found in '"
                    + Arrays.toString(basePackages)
                    + "' package. Please check your configuration.");
        } else {
            processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }

    public void registerFilters() {
        boolean acceptAllInterfaces = true;

        if (this.annotationClass != null) {
            addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
            acceptAllInterfaces = false;
        }

        if (acceptAllInterfaces) {
            addIncludeFilter(new TypeFilter() {
                @Override
                public boolean match(MetadataReader metadataReader,
                                     MetadataReaderFactory metadataReaderFactory) {
                    return true;
                }
            });
        }

        // exclude package-info.java
        addExcludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader,
                                 MetadataReaderFactory metadataReaderFactory)
                    throws IOException {
                String className = metadataReader.getClassMetadata()
                        .getClassName();
                boolean matchPan = className.endsWith("package-info");
                return matchPan;
            }
        });
    }

    private void processBeanDefinitions(
            Set<BeanDefinitionHolder> beanDefinitions) {
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder holder : beanDefinitions) {
            definition = (GenericBeanDefinition) holder.getBeanDefinition();
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            definition.setBeanClass(this.rpcFactoryBean.getClass());
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }

    /**
     * 判断接口类是否被继承 true已被继承，false没有
     */
    public boolean isClassImpl(String interfaceClassName) {
//        String packPath = interfaceClassName.substring(0,interfaceClassName.lastIndexOf("."));
        String packPath = packPageName;
        Set<Class<?>> allClassSet = ClassUtil.getClasses(packPath);
        if (allClassSet != null) {
            for (Class class1 : allClassSet) {
                Class<?> interfaces[] = class1.getInterfaces();
                for (Class<?> inte : interfaces) {
                    if (inte.getName().equals(interfaceClassName)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 业务判断：接口类是否是service接口 ture是，false否
     * 可以多个层级
     */
    public boolean isServiceIntergerClass(String interfaceClassName) {
//        String packName = interfaceClassName.substring(0,interfaceClassName.lastIndexOf("."));
//        packName=packName.substring(packName.lastIndexOf(".")+1,packName.length());
        try {
//            if("service".equals(packName)){
//                return true;
//            }
            //是否是按规范在service包名下
            if (interfaceClassName.indexOf(".service.") > -1) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }


    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
//        System.out.println(beanDefinition.getMetadata().getClassName());
        boolean pan = beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
        try {
            if (pan) {
                //业务判断：是否是service接口
                if (!isServiceIntergerClass(beanDefinition.getMetadata().getClassName())) {
                    return false;
                }
                //判断是否有类去实现该接口
                if (isClassImpl(beanDefinition.getMetadata().getClassName())) {
                    return false;
                }
            }
        } catch (Exception e) {
            logger.info("类解析出错，说明是不知名类");
            return false;
        }
        return pan;
    }
}
